package cms.web.filter;


import cms.bean.setting.SystemSetting;
import cms.bean.user.AccessUser;
import cms.common.SystemConstant;
import cms.service.setting.SettingService;
import cms.service.template.TemplateService;
import cms.service.user.UserService;
import cms.utils.IpAddress;
import cms.utils.UUIDUtil;
import cms.utils.threadLocal.AccessUserThreadLocal;
import cms.utils.threadLocal.CSRFTokenThreadLocal;
import cms.utils.threadLocal.TemplateThreadLocal;
import cms.manage.AccessSourceDeviceManage;
import cms.manage.CSRFTokenManage;
import cms.manage.PageViewManage;
import cms.manage.template.TemplateMain;
import cms.manage.ThirdPartyManage;
import cms.web.action.user.RoleAnnotation;
import cms.manage.user.UserManage;
import cms.manage.user.UserRoleManage;
import cms.web.taglib.Configuration;
import cms.web.util.TraceIdUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.log4j.MDC;
import org.apache.logging.log4j.ThreadContext;
import org.queryString.util.MultiMap;
import org.queryString.util.UrlEncoded;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static cms.common.SystemConstant.LayoutType.*;


/**
 * 模板拦截器(将模板显示功能加入指定的页面中)
 */
@Slf4j
public class TempletesInterceptor extends HandlerInterceptorAdapter {
	@Resource
	TemplateService templateService;
	@Resource
	SettingService settingService;
	@Resource
	AccessSourceDeviceManage accessSourceDeviceManage;
	@Resource
	CSRFTokenManage csrfTokenManage;
	@Resource
	PageViewManage pageViewManage;

	@Autowired
	private HttpSession session;
	
	@Resource UserRoleManage userRoleManage;
	@Resource TemplateMain templateMain;
	//?  匹配任何单字符
	//*  匹配0或者任意数量的字符
	//** 匹配0或者更多的目录
	//后台URL
	private final AntPathRequestMatcher[] antPathRequestMatchers = {
			new AntPathRequestMatcher("/control/**"),
			new AntPathRequestMatcher("/admin/**"),
			new AntPathRequestMatcher("/captcha/**"),//生成验证码
			new AntPathRequestMatcher("/checkCaptcha")//校验验证码
	};

	/**
	 * preHandle()方法在业务处理器处理请求之前被调用 
	 */
	  
	public boolean preHandle(HttpServletRequest request,HttpServletResponse response, 
			Object handler) throws Exception {
		if(log.isInfoEnabled()) {
			log.info(request.getRequestURI() + " -- " + request.getQueryString() + " -- " + request.getMethod());
		}
		MDC.put("traceId", TraceIdUtil.createTraceId());//保证wf内日志中打印traceId
		MDC.put("startTime", String.valueOf(System.currentTimeMillis()));
		//拦截用户角色处理 注解参考： @RoleAnnotation(resourceCode=ResourceEnum._2001000)
		if(handler instanceof HandlerMethod){
			HandlerMethod  handlerMethod= (HandlerMethod) handler;
	        Method method=handlerMethod.getMethod();
	        RoleAnnotation roleAnnotation = method.getAnnotation(RoleAnnotation.class);
	        if(roleAnnotation != null){
	        	boolean flag = userRoleManage.checkPermission(roleAnnotation.resourceCode(),null);
	        	if(!flag){
	        		 return false;
	        	}
	        }
		}

		//设置自定义标签的URL
		if(request != null){
			if (Configuration.getPath() == null || "".equals(Configuration.getPath())) {
				Configuration.setPath(request.getContextPath());
			}
			//添加sessionId
			TemplateThreadLocal.addRuntimeParameter("sessionId", session.getId());

			//Cookies
			TemplateThreadLocal.addRuntimeParameter("cookies", request.getCookies());

			//URI
			TemplateThreadLocal.addRuntimeParameter("requestURI", request.getRequestURI());

			//URL参数
			TemplateThreadLocal.addRuntimeParameter("queryString", request.getQueryString());

			//IP
			TemplateThreadLocal.addRuntimeParameter("ip", IpAddress.getClientIpAddress(request));

			//获取登录用户(user/开头的URL才有值)
			AccessUser accessUser = AccessUserThreadLocal.get(session, false);
			if (null != accessUser) {
				TemplateThreadLocal.addRuntimeParameter("accessUser", accessUser);
			}
		}
		//设置令牌
		csrfTokenManage.setToken(request, response);

		SystemSetting systemSetting = settingService.findSystemSettingCache();

		if (systemSetting.getCloseSite().equals(SystemConstant.SiteStatus.CLOSE.getValue())) {//3.全站关闭
			boolean backstageFlag = false;
			//后台URL
			for (AntPathRequestMatcher rm : antPathRequestMatchers) {
				if (rm.matches(request)) {
					backstageFlag = true;
					break;
				}
			}
			if (backstageFlag == false) {
				String baseURI = Configuration.baseURI(request.getRequestURI(), request.getContextPath());
				//删除后缀
				baseURI = StringUtils.substringBeforeLast(baseURI, ".");
				if (!baseURI.equalsIgnoreCase("message")) {
					response.sendRedirect(Configuration.getUrl(request) + "message");
					return false;
				}
			}
		}
		return true;
	}

	/**
	 * postHandle()方法在业务处理器处理请求之后被调用
	 */
	public void postHandle(HttpServletRequest request, HttpServletResponse response,
						   Object handler, ModelAndView modelAndView) throws Exception {
		String mav = "";
		if (modelAndView != null) {
			mav = modelAndView.getViewName();
		}

		//如果视图方法返回值为templates开头,就将模板显示功能加入页面中
		if (StringUtils.isNotBlank(mav) && mav.length() > 10) {
			//	if(mav.matches("^templates/.*$")){
			String begin = mav.substring(0, 9);//取得templates
			//如果以templates开头
			if (StringUtils.equals("templates", begin)) {
				//统计访问量
				pageViewManage.addPV(request);

				//获取URL参数 get方法抛的数据有效，post方法传的参数getQueryString将什么都得不到
				String queryString = request.getQueryString();
				if (StringUtils.isNotBlank(queryString)) {
					MultiMap<String> values = new MultiMap<String>();
					UrlEncoded.decodeTo(queryString, values, "UTF-8");
					Iterator iter = values.entrySet().iterator();
					while (iter.hasNext()) {
						Map.Entry e = (Map.Entry) iter.next();
						if (e.getValue() != null) {
							if (e.getValue() instanceof List) {
								List<String> valueList = (List) e.getValue();
								if (CollectionUtils.isNotEmpty(valueList)) {
									for (String value : valueList) {
										if (value != null && !"".equals(value.trim())) {
											//TODO 统一添加了前缀
											request.setAttribute("url_" + e.getKey(), value.trim());//分页
											break;
										}
									}
								}
							}
						}
					}
				}

				//取得请求页面名称
				String requestName = StringUtils.substringAfterLast(mav, "/");//返回最后一个指定字符串之后的所有字符

				//添加到模板参数线程变量
				TemplateThreadLocal.setLayoutFile(requestName + ".html");

				String dirName = templateService.findTemplateDirCache();

				SystemSetting systemSetting = settingService.findSystemSettingCache();
				////如果第一次打开时还没设置Cookie
				String csrfToken = StringUtils.defaultIfBlank(csrfTokenManage.getToken(request),CSRFTokenThreadLocal.get());
				//获取登录用户
				AccessUser accessUser =  AccessUserThreadLocal.get(session, false);
				//执行自定义标签
				request.setAttribute("baseURL", Configuration.getUrl(request));//系统路径
				request.setAttribute("commonPath", "common/" + dirName + "/" + accessSourceDeviceManage.accessDevices(request) + "/");//资源路径
				request.setAttribute("contextPath", request.getContextPath());//系统虚拟目录
				request.setAttribute("suffix", Configuration.getSuffix());//取得系统后缀名
				request.setAttribute("templateDir", dirName);//模板目录名称
				request.setAttribute("title", systemSetting.getTitle());//站点名称
				request.setAttribute("keywords", systemSetting.getKeywords());//站点关键词
				request.setAttribute("description", systemSetting.getDescription());//站点描述
				request.setAttribute("systemUser", accessUser);//登录用户
				request.setAttribute("baseURI", Configuration.baseURI(request.getRequestURI(), request.getContextPath()));//系统资源标识符
				request.setAttribute("token", csrfToken);
				request.setAttribute("identificationNumber", UUIDUtil.getUUID32());//识别号：用来区别每次请求


//	    			WeChatConfig weChatConfig = thirdPartyManage.queryWeChatConfig();
//	    	    	if(weChatConfig != null){
//	    	    		request.setAttribute("weixin_oa_appid",weChatConfig.getOa_appID());//微信公众号appid
//	    	    	}

				if (StringUtils.isNotBlank(requestName)) {
					if (StringUtils.startsWith(requestName, "blank_")) {//空白页
						//调用公共模板处理类
						Map<String, Object> roots = templateMain.list(BLANK_PAGE.getValue(), requestName + ".html", request);//4.空白页
						modelAndView.addAllObjects(roots);
					}else if (StringUtils.startsWith(requestName, "column_")) {//站点栏目详细页
						//调用公共模板处理类
						Map<String, Object> roots = templateMain.list(SITE_MENU_PAGE.getValue(), requestName + ".html", request);//7.站点栏目详细页
						modelAndView.addAllObjects(roots);
					} else {//默认页
						Map<String, Object> roots = templateMain.list(DEFAULT_PAGE.getValue(), requestName + ".html", request);//1.默认页
						modelAndView.addAllObjects(roots);
					}

				}

				//公共页(引用版块值)辅助类
				Map<String, Object> publicAuxiliaryMap = templateMain.publicQuoteCall(mav + ".html", request);
				modelAndView.addAllObjects(publicAuxiliaryMap);
				//公共页(生成新引用页)辅助类
				Map<String, Object> newPublicAuxiliaryMap = templateMain.newPublic(mav + ".html", request);
				modelAndView.addAllObjects(newPublicAuxiliaryMap);
			}
		}
	}   
	/**
	 *  afterCompletion()方法在DispatcherServlet完全处理完请求后被调用
	 */
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {
    	//删除当前线程副本
    	TemplateThreadLocal.removeThreadLocal();
    	AccessUserThreadLocal.removeThreadLocal();
    	CSRFTokenThreadLocal.removeThreadLocal();
		try {
			long start = NumberUtils.toLong(ThreadContext.get("startTime"));
			if(log.isInfoEnabled())
				log.info("uri={}, type=wf_end, cost={}, response:{}", request.getRequestURI(), (System.currentTimeMillis() - start),handler);
		} catch (Exception e) {
			log.error("过滤器 exception", e);
		} finally {
			MDC.remove("startTime");
			MDC.remove("traceId");
		}
	}   
}
